import datetime
import logging
import os
import shutil
import uuid
import zipfile
from typing import Optional, Dict

import aiohttp
import requests
import tempfile

from fastapi import FastAPI, HTTPException
from neo4j import GraphDatabase
from pathlib import Path

from openai import BaseModel

from app.config import settings

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 初始化FastAPI应用
app = FastAPI(title="zip 导入 neo4j", description="解析ZIP并导入Neo4j（含完整字段属性）")
# 请求/响应模型
class ZipToNeo4jRequest(BaseModel):
    zip_url: str


class ZipToNeo4jResponse(BaseModel):
    status: str = "success"
    message: Optional[str] = None
    data: Optional[Dict] = None


class ZipToNeo4jService:
    def __init__(self):
        os.makedirs(settings.temp_dir_root, exist_ok=True)
        self.driver = None

    def _init_neo4j_driver(self):
        if not self.driver:
            try:
                self.driver = GraphDatabase.driver(
                    settings.neo4j_uri,
                    auth=(settings.neo4j_user, settings.neo4j_password)
                )
                self.driver.verify_connectivity()
                logger.info("Neo4j驱动初始化成功")
            except Exception as e:
                logger.error(f"Neo4j驱动初始化失败: {str(e)}")
                raise HTTPException(status_code=500, detail=f"无法连接到Neo4j: {str(e)}")

    async def download_zip(self, url:str) -> str:
        # 保持不变（文件下载逻辑）
        if not url.startswith("http://") and settings.dify_prefix:
            full_url = settings.dify_prefix.rstrip("/") + "/" + url.lstrip("/")
        else:
            full_url = url

        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        unique_id = uuid.uuid4().hex[:8]
        temp_dir = os.path.join(settings.temp_dir_root, f"tmp_{timestamp}_{unique_id}")
        os.makedirs(temp_dir, exist_ok=True)

        filename = url.split("/")[-1]
        if not filename.endswith(".zip"):
            filename = f"er_import_{unique_id}.zip"
        file_path = os.path.join(temp_dir, filename)

        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(full_url) as resp:
                    if resp.status != 200:
                        logger.error(f"zip文件下载失败，URL: {full_url}，状态码: {resp.status}")
                        raise HTTPException(status_code=400, detail=f"zip文件下载失败，状态码: {resp.status}")
                    with open(file_path, "wb") as f:
                        while True:
                            chunk = await resp.content.read(1024 * 1024)
                            if not chunk:
                                break
                            f.write(chunk)
            logger.info(f"zip文件下载成功，路径: {file_path}")
            return file_path
        except Exception as e:
            logger.error(f"下载过程异常: {str(e)}")
            raise HTTPException(status_code=500, detail=f"文件下载失败: {str(e)}")

    def execute_cypher_from_zip(self,zip_path :str):
        # 读取ZIP文件
        self._init_neo4j_driver()
        driver = self.driver
        with zipfile.ZipFile(zip_path, 'r') as z:
            # 查找所有.cypher文件
            cypher_files = [f for f in z.namelist() if f.endswith('.cypher')]

            if not cypher_files:
                raise FileNotFoundError("在ZIP文件中未找到.cypher文件")

            # 只处理找到的第一个.cypher文件
            cypher_filename = cypher_files[0]
            with z.open(cypher_filename) as cypher_file:
                cypher_script = cypher_file.read().decode('utf-8')

            print(f"从 {cypher_filename} 读取Cypher脚本成功")


        try:
            with driver.session() as session:
                # 按分号分割语句并逐条执行
                statements = [stmt.strip() for stmt in cypher_script.split(';') if stmt.strip()]

                for i, statement in enumerate(statements):
                    if not statement:
                        continue

                    print(f"执行语句 #{ i +1}/{len(statements)}: {statement[:50]}{'...' if len(statement) > 50 else ''}")

                    try:
                        result = session.run(statement)
                        # 获取并打印执行摘要
                        summary = result.consume()
                        if summary.counters.contains_updates:
                            updates = [
                                f"节点: +{summary.counters.nodes_created}",
                                f"关系: +{summary.counters.relationships_created}",
                                f"属性: +{summary.counters.properties_set}",
                                f"标签: +{summary.counters.labels_added}"
                            ]
                            print(f"  更新统计: {', '.join([u for u in updates if '+0' not in u])}")
                    except Exception as e:
                        print(f"执行语句时出错: {str(e)}")
                        print(f"问题语句: {statement[:200]}")
                        raise

            print(f"成功执行 {len(statements)} 条Cypher语句")
        finally:
            driver.close()


    async def process(self, zip_url: str) :
        """完整处理流程"""
        zip_path = await self.download_zip(zip_url)
        self.execute_cypher_from_zip(zip_path)
        # 清理临时文件
        try:
            shutil.rmtree(os.path.dirname(zip_path))
            logger.info(f"临时文件已清理: {os.path.dirname(zip_path)}")
        except Exception as e:
            logger.warning(f"临时文件清理失败: {str(e)}")


